package org.gpp.proj1.ui.gui.ingame;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import org.fenggui.Button;
import org.fenggui.ComboBox;
import org.fenggui.Label;
import org.fenggui.composites.TextArea;
import org.fenggui.composites.Window;
import org.fenggui.event.ButtonPressedEvent;
import org.fenggui.event.IButtonPressedListener;
import org.fenggui.io.IOStreamException;
import org.fenggui.layout.StaticLayout;
import org.fenggui.xml.theme.XMLTheme;
import org.gpp.proj1.communication.CommunicationException;
import org.gpp.proj1.menu.fenggui.FengJMEInputHandler;
import org.gpp.proj1.robot.Robot;
import org.gpp.proj1.ui.controller.ISRGUIController;

import com.jme.input.MouseInput;
import com.jme.renderer.Renderer;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameState;

/**
 * 
 * @author Paolo Victor, paolovictor@gmail.com
 *
 */
public class MenuState extends BasicGameState implements IButtonPressedListener {

	public static final String MENU_STATE_NAME = "menu";

	private static final String SEND_MESSAGE = "Send chat";

	private static final String END_TURN = "End turn";
	
	private static final String MOVE_ROBOT = "Move robot";
	
	private static final String CONFIRM = "Yes";
	
	private static final String NOT_CONFIRM = "No";

	private static final String ATTACK = "Attack";
	
	private static final String EXECUTE_ATTACK = "Execute Attack";
	
	private static final String CANCEL_ATTACK = "Cancel Attack";

	private FengJMEInputHandler fengInput;

	private org.fenggui.Display disp;

	private Window chatFrame;

	private Window turnFrame;

	private Window primaryActionsWindow;
	
	private Window robotAttackWindow;

	private TextArea chatTextArea;

	private TextArea chatMessageTextArea;

	private final ISRGUIController controller;

	private Label currentTurnPlayerLabel;

	private Label currentTurnRobotLabel;

	private Button endTurnButton;

	private Button moveRobotButton;
	
	private Button attackButton;
	
	private ComboBox attacks;

	private final GameViewportManager manager;

	private boolean showingConfirmation = false;

	private boolean ownTurn;

	private Robot robot;
	
	public MenuState( ISRGUIController controller, GameViewportManager manager ) {
		super( MENU_STATE_NAME );

		this.controller = controller;
		this.manager = manager;

		initInput();

//		rootNode.setLightCombineMode(LightState.OFF);
		rootNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);
		rootNode.updateRenderState();
		rootNode.updateGeometricState(0, true);

		this.initGUI();
	}

	private void initGUI() {
		disp = new org.fenggui.Display(new org.fenggui.render.lwjgl.LWJGLBinding());

		try {
			org.fenggui.FengGUI.setTheme(new XMLTheme("data/themes/QtCurve/QtCurve.xml"));
		} catch (IOException e) {
		} catch (IOStreamException e) {
		}

		fengInput = new FengJMEInputHandler(disp);

		this.turnFrame = new Window(false, false, false);
		this.disp.addWidget( turnFrame );
		this.turnFrame.setTitle("Turn info");
		this.turnFrame.setX( 5 );
		this.turnFrame.setY( disp.getHeight() - 75 );
		this.turnFrame.setSize( 220, 70 );
		this.turnFrame.setShrinkable(false);
		this.turnFrame.setExpandable( false );
		this.turnFrame.getAppearance().setBorder( null );
		this.turnFrame.updateMinSize();
		this.turnFrame.getContentContainer().setLayoutManager(new StaticLayout());

		this.currentTurnPlayerLabel = new Label("Player: Unknown");
		this.currentTurnPlayerLabel.setXY( 5, 35 );
		this.currentTurnPlayerLabel.setWidth( 210 );
		this.currentTurnPlayerLabel.updateMinSize();

		this.currentTurnRobotLabel = new Label("Robot: Unknown");
		this.currentTurnRobotLabel.setXY( 5, 10 );
		this.currentTurnRobotLabel.setWidth( 210 );
		this.currentTurnRobotLabel.updateMinSize();

		this.turnFrame.getContentContainer().addWidget( this.currentTurnPlayerLabel );
		this.turnFrame.getContentContainer().addWidget( this.currentTurnRobotLabel );		

		this.chatFrame = new Window(false, false, false);
		this.disp.addWidget( chatFrame );
		this.chatFrame.setTitle("Chat");
		this.chatFrame.setX( 5 );
		this.chatFrame.setY( 5 );
		this.chatFrame.setSize( 400, 150 );
		this.chatFrame.setShrinkable(false);
		this.chatFrame.setExpandable( false );
		this.chatFrame.getAppearance().setBorder( null );
		this.chatFrame.updateMinSize();		
		this.chatFrame.getContentContainer().setLayoutManager(new StaticLayout());

		Button sendMessageButton = new Button();
		sendMessageButton.setText( SEND_MESSAGE );
		sendMessageButton.setSize( sendMessageButton.getMinWidth() + 5, sendMessageButton.getMinHeight() );
		sendMessageButton.setXY( 310, 5 );
		sendMessageButton.addButtonPressedListener( this );

		this.chatFrame.getContentContainer().addWidget( sendMessageButton );

		this.chatTextArea = new TextArea();
		this.chatTextArea.setSize( 390, 100 );
		this.chatTextArea.setShrinkable(false);
		this.chatTextArea.setXY( 5, sendMessageButton.getMinHeight() + 5 );
		this.chatTextArea.getTextEditor().setEnabled( false );

		this.chatFrame.getContentContainer().addWidget( chatTextArea );

		this.chatMessageTextArea = new TextArea();
		this.chatMessageTextArea.setSize( 300, 24 );
		this.chatMessageTextArea.setShrinkable(false);
		this.chatMessageTextArea.setXY( 5, 5 );
		this.chatMessageTextArea.getTextEditor().setMultiline( false );

		this.chatFrame.getContentContainer().addWidget( chatMessageTextArea );

		this.primaryActionsWindow = new Window(false, false, false);
		this.primaryActionsWindow.setTitle("Actions");
		this.primaryActionsWindow.setX( 410 );
		this.primaryActionsWindow.setY( 5 );
		this.primaryActionsWindow.setSize( 150, 150 );
		this.primaryActionsWindow.setShrinkable(false);
		this.primaryActionsWindow.setExpandable( false );
		this.primaryActionsWindow.getAppearance().setBorder( null );
		this.primaryActionsWindow.updateMinSize();		
		this.primaryActionsWindow.getContentContainer().setLayoutManager(new StaticLayout());

		endTurnButton = new Button();
		endTurnButton.setText( END_TURN );
		endTurnButton.setSize( 140, endTurnButton.getMinHeight() );
		endTurnButton.setXY( 5, 5 );
		endTurnButton.addButtonPressedListener( this );
		
		moveRobotButton = new Button();
		moveRobotButton.setText( MOVE_ROBOT );
		moveRobotButton.setSize( 140, moveRobotButton.getMinHeight() );
		moveRobotButton.setXY( 5, endTurnButton.getMinHeight() + 5 );
		moveRobotButton.addButtonPressedListener( this );
		
		attackButton = new Button();
		attackButton.setText( ATTACK );
		attackButton.setSize( 140, attackButton.getMinHeight() );
		attackButton.setXY( 5, moveRobotButton.getHeight() + endTurnButton.getMinHeight() + 5 );
		attackButton.addButtonPressedListener( this );

		this.primaryActionsWindow.getContentContainer().addWidget( endTurnButton );
		this.primaryActionsWindow.getContentContainer().addWidget( moveRobotButton );
		this.primaryActionsWindow.getContentContainer().addWidget( attackButton );

		this.disp.layout();
	}

	/**
	 * Inits the input handler we will use for navigation of the menu.
	 */
	protected void initInput() {

		MouseInput.get().setCursorVisible( true );
	}

	/**
	 * Updates input and button.
	 * 
	 * @param tpf The time since last frame.
	 * @see GameState#update(float)
	 */
	@Override
	public void update(float tpf) {

		fengInput.update( tpf );
	}

	@Override
	public void render( float tpf ) {

		super.render( tpf );

		disp.display();
	}

	/**
	 * Invoked by the model when a chat message arrives
	 * 
	 * @param alias
	 * @param message
	 */
	public void chatArrived( String alias, String message ) {

		if( this.chatTextArea != null ) {
			this.chatTextArea.appendText( "<" + alias + "> " + message + "\n" );
		}
	}

	public void buttonPressed(ButtonPressedEvent evt) {

		try {			
			
			String triggerText = evt.getTrigger().getText();
			if( triggerText.equals( SEND_MESSAGE ) && this.chatMessageTextArea != null
					&& !this.chatMessageTextArea.getText().trim().equals( "" ) ) {
				
				this.controller.sendChatMessage( this.chatMessageTextArea.getText() );
			} else if( triggerText.equals( END_TURN ) ) {
				
				this.disp.removeWidget( primaryActionsWindow );
				this.manager.closeMovementSelector();
				this.moveRobotButton.setEnabled( true );				
				this.controller.endTurn();
				
			} else if( triggerText.equals( MOVE_ROBOT ) ) {
				
				this.manager.openMovementSelector();				
				this.disp.removeAllWidgets();
			} else if( triggerText.equals( CONFIRM ) ) {
				if( this.showingConfirmation ) {
					this.disp.removeAllWidgets();
					this.disp.layout();
					this.manager.selectionConfirmed();
					
					this.moveRobotButton.setEnabled( false );
					this.moveRobotButton.layout();
					
					this.showingConfirmation = false;
				}
			} else if( triggerText.equals( NOT_CONFIRM ) ) {
				if( this.showingConfirmation ) {
					this.disp.removeAllWidgets();
					this.disp.layout();
					this.manager.selectionUnconfirmed();
					
					this.showingConfirmation = false;
				}
			} else if( triggerText.equals( ATTACK ) ) {
				this.disp.removeWidget( this.primaryActionsWindow );
				this.disp.addWidget( this.robotAttackWindow );
				this.disp.layout();
			} else if( triggerText.equals( CANCEL_ATTACK ) ) {
				this.disp.removeWidget( this.robotAttackWindow );
				this.disp.addWidget( this.primaryActionsWindow );
				this.disp.layout();
			} else if( triggerText.equals( EXECUTE_ATTACK ) ) {
				
				this.manager.displayTargetSelectionField();
				this.disp.removeAllWidgets();
			}
		} catch (CommunicationException e) {
			this.chatMessageTextArea.appendText( "Message failed\n" );
		}
	}

	public void notifyTurn( String alias ) {

		this.currentTurnPlayerLabel.setText( "Player: " + alias);
		this.currentTurnPlayerLabel.updateMinSize();
		
		this.ownTurn = false;
	}

	private void createRobotAttacksMenu() {
		
		this.robot = this.manager.getCurrentTurnRobot();

		if( this.robot != null ) {			
			Map<String, List<String>> attackMap = robot.getExecutableActions();
			
			this.attacks = new ComboBox();
			this.attacks.setSize( 200, this.attacks.getMinHeight() );
			this.attacks.setXY( 5, 35 );
			
			for( String group : attackMap.keySet() ) {
				for( String action : attackMap.get( group ) ) {
					this.attacks.addItem( action + " [" + group + "]" );
				}
			}
			
			robotAttackWindow = new Window(false, false, false);		
			robotAttackWindow.setTitle("Attacks");
			robotAttackWindow.setX( disp.getWidth() - 215 );
			robotAttackWindow.setY( 40 );
			robotAttackWindow.setSize( 210, 80 );
			robotAttackWindow.setShrinkable(false);
			robotAttackWindow.setExpandable( false );
			robotAttackWindow.getAppearance().setBorder( null );
			robotAttackWindow.updateMinSize();		
			robotAttackWindow.getContentContainer().setLayoutManager(new StaticLayout());
			
			Button confirmButton = new Button();
			confirmButton.setText( EXECUTE_ATTACK );
			confirmButton.setSize( confirmButton.getMinWidth(), confirmButton.getMinHeight() );
			confirmButton.setXY( 5, 5 );
			confirmButton.addButtonPressedListener( this );
			
			Button cancelAttackButton = new Button();
			cancelAttackButton.setText( CANCEL_ATTACK );
			cancelAttackButton.setSize( cancelAttackButton.getMinWidth(), cancelAttackButton.getMinHeight() );
			cancelAttackButton.setXY( confirmButton.getMinWidth() + 5, 5 );
			cancelAttackButton.addButtonPressedListener( this );
			
			robotAttackWindow.addWidget( this.attacks );
			robotAttackWindow.addWidget( confirmButton );
			robotAttackWindow.addWidget( cancelAttackButton );
		}
	}

	public void notifyOwnTurn() {

		this.currentTurnPlayerLabel.setText( "Your turn!");
		this.currentTurnPlayerLabel.updateMinSize();

		this.moveRobotButton.setEnabled( true );
		this.attackButton.setEnabled( true );
		
		this.disp.addWidget( this.primaryActionsWindow );
		this.disp.layout();
		
		this.ownTurn = true;
	}

	public void notifyRobotTurn(String robotName) {

		this.currentTurnRobotLabel.setText( "Robot: " + robotName);
		this.currentTurnRobotLabel.updateMinSize();

		if( ownTurn ) {
			this.createRobotAttacksMenu();
		}
	}

	public void selectionCancelled() {

		this.disp.addWidget( chatFrame );
		this.disp.addWidget( primaryActionsWindow );
		this.disp.addWidget( turnFrame );
		this.disp.layout();
	}

	public void askForConfirmation() {
		this.disp.removeAllWidgets();
		
		this.showingConfirmation = true;
		
		Window confirmation = new Window(false, false, false);		
		confirmation.setTitle("Confirm action?");
		confirmation.setX( disp.getWidth() / 2 + 100 );
		confirmation.setY( disp.getHeight() / 2 + 100 );
		confirmation.setSize( 140, 60 );
		confirmation.setShrinkable(false);
		confirmation.setExpandable( false );
		confirmation.getAppearance().setBorder( null );
		confirmation.updateMinSize();		
		confirmation.getContentContainer().setLayoutManager(new StaticLayout());
		
		Button confirmButton = new Button();
		confirmButton.setText( CONFIRM );
		confirmButton.setSize( 65, confirmButton.getMinHeight() );
		confirmButton.setXY( 5, 5 );
		confirmButton.addButtonPressedListener( this );
		
		Button cancelButton = new Button();
		cancelButton.setText( NOT_CONFIRM );
		cancelButton.setSize( 65, cancelButton.getMinHeight() );
		cancelButton.setXY( 70, 5 );
		cancelButton.addButtonPressedListener( this );

		confirmation.addWidget( confirmButton );
		confirmation.addWidget( cancelButton );
		
		this.disp.addWidget( confirmation );
		this.disp.layout();
	}

	public void showMenu() {

		this.disp.addWidget( chatFrame );
		this.disp.addWidget( turnFrame );
		
		if( this.ownTurn ) {
			this.disp.addWidget( primaryActionsWindow );
		}
		
		this.disp.layout();
	}

	public String getSelectedPart() {
		
		if( this.attacks == null ) {
			return null;
		}
		
		return this.attacks.getLabel().getText().split( "[\\[\\] ]+" )[1];
	}

	public String getSelectedAction() {
		
		if( this.attacks == null ) {
			return null;
		}
		
		return this.attacks.getLabel().getText().split( "[\\[\\] ]+" )[0];
	}
}